#ifndef __REDIS_CON_POOL_H__
#define __REDIS_CON_POOL_H__

#include <memory>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <atomic>

#include <hiredis/hiredis.h>

//Redis 连接池
class RedisConPool 
{
public:
    struct ContextDeleter 
    {
        void operator()(redisContext* ctx) const noexcept 
        {
            if (ctx) redisFree(ctx);
        }
    };
    using ContextPtr = std::unique_ptr<redisContext, ContextDeleter>;

    // 在析构时自动归还连接
    class ConnectionHandle 
    {
    public:
        ConnectionHandle(RedisConPool& pool, ContextPtr ctx)
        :_pool(pool)
        ,_ctx(std::move(ctx)) 
        {}
            
        ~ConnectionHandle() 
        {
            if (_ctx) _pool._ReturnConnection(std::move(_ctx));
        }
        redisContext* get() const { return _ctx.get(); }
        redisContext* operator->() const { return _ctx.get(); }
        redisContext& operator*() const { return *_ctx; }
        ConnectionHandle(const ConnectionHandle&) = delete;
        ConnectionHandle& operator=(const ConnectionHandle&) = delete;

        ConnectionHandle(ConnectionHandle&& other) noexcept
            : _pool(other._pool), _ctx(std::move(other._ctx)) {}
    private:
        RedisConPool& _pool;
        ContextPtr _ctx;
    };

public:

    // RedisConPool(size_t poolSize, const char* host, int port, const char* pwd)
    //     : _b_stop(false), _poolSize(poolSize), _host(host), _port(port), pwd_(pwd) 
    RedisConPool();

    ~RedisConPool() { Close(); }

    // 获取链接
    ConnectionHandle GetConnection();

    void show();

    void Close();
private:
    // 创建 Redis 连接
    ContextPtr _CreateContext();

    // 归还链接
    void _ReturnConnection(ContextPtr ctx);

private:
    std::atomic_bool _b_stop;
    size_t _poolSize;
    int _port;
    std::string _host;
    std::string _pwd;

    std::queue<ContextPtr> _connections;
    std::mutex _mutex;
    std::condition_variable _cond;
};


#endif // !__REDIS_CON_POOL_H__